iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
AI Engineering

128GB 統一記憶體的三十天:DGX Spark 地端 LLM 與生成式 AI 部署實戰系列 第 23

Day 23|ComfyUI 部署與 NFS 模型庫整合:把集中管理的哲學帶進生圖世界

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20260905/20141816KPcKtsXTlM.png

作圖做影片好用的地端 AI 首選 - ComfyUI

連續七天的引擎與 agent 硬仗打完了,本週進生成媒體週。節奏會輕一點,但方法論不變,今天要做的事跟 Day 5 一模一樣,只是對象從 LLM 權重換成 diffusion model、LoRA 與 VAE,機器從一台換成兩台。

先講為什麼生成媒體值得地端。NVIDIA 在本週 2026 IFA 的新聞稿裡用了一個詞叫「token anxiety」,創作者用雲端生圖服務時那種每按一次就在燒點數的焦慮。地端沒有這回事,一張圖跑十次改二十次都是電費,而且素材、客戶的品牌資產、還沒發布的產品照,全部不出門。對於需要製作圖片、影片的廣告工作者、社群小編、內容創作者來說,這兩點都是實際需求。

ComfyUI,我個人是最推薦這個來在地端 AI 產圖片、生影片,它的生態系、擴充性與整合度最好。

兩個節點,兩種角色

本系列的生成媒體環境有兩台機器分工:

NVIDIA DGX Spark GB10 當重型節點。 128 GB 統一記憶體對生圖的意義跟對 LLM 一樣,大模型全精度放得下,理論上多個模型可以同時常駐不必反覆載入(這個「理論上」等一下會被實測打臉)。代價是 Day 2 講過的頻寬,擴散模型的每一步去噪都是算力加頻寬的組合。

128GB 桌機當快手節點。 RTX 5060 Ti 16 GB 加 128 GB 系統記憶體,Day 22 剛打完對決,今天以生圖節點的身分留下。

這兩台不是「今天各自安裝 ComfyUI」。 桌機上的 ComfyUI 早就在跑了,是官方的 Windows 免安裝版,Spark 上的也早就在跑,只是版本停在 0.31.0 之後的第 25 個 commit。今天做的是把 Spark 升到 v0.34.3,讓兩台站在同一個版本上,就會是相同的立足點做比較測試。

Spark 這邊是裸機 venv 而非容器,採用 PyTorch 2.9.1+cu130。aarch64 上的小問題只有一個,而且它每次啟動都會出現:

/home/.../torch/cuda/__init__.py:283: UserWarning:
    Found GPU0 NVIDIA GB10 which is of cuda capability 12.1.
    Minimum and Maximum cuda capability supported by this version of PyTorch is
    (8.0) - (12.0)

GB10 是 sm_121,官方 wheel 只認到 sm_120,所以它走相容路徑。這條警告從 Day 8 到現在沒有變過,實務上不影響生圖,但它會連帶讓 ComfyUI 的 triton 後端被停用(Found comfy_kitchen backend triton: available True, disabled True),只剩 eager 後端。啟動時另外兩行值得記下來:

Total VRAM 124546 MB, total RAM 124546 MB
Using async weight offloading with 2 streams
Enabled pinned memory 112091.0

VRAM 與 RAM 是同一個數字,因為它們本來就是同一塊記憶體。這句話等一下會變成今天最有意思的那個發現。

升級本身沒有意外,但有一件事值得提醒:git reset --hard origin/master 會把你帶到未發版的 master,不是最新的釋出版。要用 tag:

git fetch --tags && git checkout v0.34.3
pip install -r requirements.txt

升完先確認自訂節點還活著。我這台裝了 MiniMax-H3 的 latent upscaler,明天要用,Import times for custom nodes 那段沒有出現 IMPORT FAILED 才算過關。

模型庫整合:一份模型,兩台共用

Day 5 立過的規矩是集中庫加 MANIFEST。今天把它延伸到 AI 產圖片。

ComfyUI 不需要你搬檔案,它有 extra_model_paths.yaml 這個機制,把外部路徑掛進模型搜尋清單。它看得到的每一款模型,都是本機碟上的副本。

今天的處置分兩步。第一步,兩台各給一份 extra_model_paths.yaml,指到同一個 NAS 目錄。Spark 走 NFS:

nas_models:
    base_path: /mnt/nas/models/
    diffusion_models: |
        diffusion_models/
        unet/
    text_encoders: text_encoders/
    clip: clip/
    vae: vae/
    loras: loras/
    controlnet: controlnet/
    clip_vision: clip_vision/
    embeddings: embeddings/
    upscale_models: upscale_models/
    style_models: style_models/
    configs: configs/

nas_comfyui_models:
    base_path: /mnt/nas/comfyui/ComfyUI/models/
    diffusion_models: diffusion_models/
    text_encoders: text_encoders/
    vae: vae/
    latent_upscale_models: latent_upscale_models/

桌機那邊同一份 NAS 目錄用 SMB 掛成磁碟機代號 Z:,內容一模一樣,只有 base_path 換成 Windows 路徑:

nas_models:
    base_path: Z:/models/
    ...
nas_comfyui_models:
    base_path: Z:/comfyui/ComfyUI/models/
    ...

第二步,把桌機獨有的那 6 款搬上 NAS,總共 78.9 GB。SMB 寫入速度落在 157.7 到 225.4 MB/s。搬完之後兩台的清單排序後逐字相同,各 27 款。

https://ithelp.ithome.com.tw/upload/images/20260905/20141816d336ZergQv.png

MANIFEST 的老規矩也適用:

# 入庫實況
path:    /mnt/nas/models/diffusion_models/flux1-krea-dev.safetensors
size:    23802958224 bytes
origin:  桌機的本機庫,2026-09-05 以 SMB 複製上架
verify:  與來源逐位元組同大小(未另計 sha256)

生圖模型的授權比 LLM 更雜(商用限制、輸出用途限制、訓練資料爭議),要做圖做影片的人,請務必在下載當下就把 license 記進去,出圖商用如果授權不對,可是會被客戶念的喔。

儲存實測:ComfyUI 的 loader 吃不吃儲存

Day 13 給了兩個判斷問題,今天拿生圖模型再驗一次。使用範例為 flux1-krea-dev_fp8_scaled.safetensors,11.90 GB。

現在的生圖權重全部是分離式,DiT 一個檔、text encoder 一個檔、VAE 一個檔。現在才測 DiT。

問題一,放得進記憶體嗎?
11.90 GB 的 DiT 加上 9.79 GB 的 T5 與 0.34 GB 的 VAE,一共約 22 GB。Spark 的 128 GB 綽綽有餘,桌機 16 GB VRAM 放不下,但 128 GB 系統記憶體接得住,所以它會卸載而不是失敗。兩台都不會掉進 Day 13 講的那個「模型逼近可用記憶體」的地獄。

問題二,loader 吃儲存速度嗎?

我原本直接對 comfy.utils.load_torch_file() 計時,那是 ComfyUI 自己的載入路徑。Spark 上的數字很漂亮:冷讀 7.55 秒(1,576 MB/s),熱讀 0.013 秒。但同一支腳本搬到桌機,同一款檔案有時 20 秒有時 1.3 秒,還出現過 9.3 GB 的檔案「載入」只花 0.089 秒,換算 104 GB/s,這當然是不可能的。ComfyUI 走的是 safetensors.safe_open 加 mmap,回來的張量是檔案的視圖,不是複本,它在不同檔案系統上會在零複製與整檔讀取之間切換,所以這個指標跨平台不能拿來比較。

所以真正該測試的反而是使用者實際等待的時間。做法是先叫 ComfyUI 把模型卸乾淨,再跑同一個工作流,用它自己 /history 回報的伺服器端時間,減掉模型常駐時的純生成時間,差額就是為了載入而多等的秒數:

curl -X POST /free -d '{"unload_models":true,"free_memory":true}'

Linux 這邊還要把頁快取也清掉,posix_fadvise(DONTNEED) 就夠,不需要 root,而且可以用 mincore 驗證真的清乾淨了,每一趟都記錄了量測前的殘留率。

同樣的檔案做純循序讀取:

路徑 循序讀取吞吐
Spark 本機 NVMe 7,090 MB/s
Spark 走 NFS(nconnect=8、readahead 15 MB) 1,122 MB/s
桌機本機碟 1,273 MB/s
桌機走 SMB 158.5 MB/s

同一台 NAS、同一條 10 GbE,NFS 拿到 1,122 MB/s,SMB 只有 158.5 MB/s。桌機的網卡是 Realtek 8127 規格是 10GbE,連線速度 10 Gbps。差距在協定與連線數,Spark 那邊 nconnect=8 是實際成立的,ss -tn 'dst NAS:2049' 數得到 8 條 ESTAB,SMB 這邊是單一連線的循序讀。

然後是實際的等待時間:

來源 Spark 桌機
純生成(模型常駐,不含載入) 18.38 秒 22.22 秒
本機碟 30.16 秒(載入多花 11.78) 26.05 秒(載入多花 3.83)
NAS 冷 38.84 秒(載入多花 20.46) 37.44 秒(載入多花 15.22)
NAS 熱(作業系統快取後) 35.46 秒(載入多花 17.08) 26.61 秒(載入多花 4.39)

https://ithelp.ithome.com.tw/upload/images/20260905/201418164b8Xv9nPyX.png

ComfyUI 屬於 Day 13 講的哪一派?

它不是 vLLM 那種只用掉 3% 磁碟能力的反序列化型,也不完全是 GGUF mmap 那種吃滿頻寬型。從 NAS 冷讀多花的 20.46 秒去算,11.90 GB 除以 20.46 秒是 582 MB/s,對上 1,122 MB/s 的尺是 52%。但這 20.46 秒裡面還混著把權重搬進運算裝置的成本,不是純 I/O,所以 52% 是上限而不是實際比例。

真正可以下的結論是,NAS 集中庫在 AI 生圖場景絕對是要使用的,雖然代價是每次換模型多等二十秒左右,而且只在冷讀取的時候要等較久。但是正常工作流中,一個工作階段裡反覆用同一款模型,所以這種第一次的等待是沒關係的。

有一個數字很反直覺,Spark 的「NAS 熱讀取」只比「NAS 冷讀取」快 3.38 秒。照理說頁快取命中應該幾乎免費,我查了量測前的殘留率才知道原因,這款 11.90 GB 的權重,在下一次載入前已經被擠掉了三分之二,殘留率只有 26.7% 到 37.0%。一台 122 GB 的機器留不住一款 12 GB 的檔案 ? 很反常吧? 這是因為 ComfyUI 自己把 112 GB 釘成了 pinned memory。順便提醒一下,Day 13 文章中,教大家使用的 readahead,有在 Spark 上設定過這個的人,這次的 AI 產圖載入同樣也一起受惠加速。

桌機則不同,Windows 版本並沒有無痛清頁快取的做法,所以那格的「冷讀取」是「本次開機後首次讀取」,而且只有一個樣本。Spark 的每一格都是 5 趟中位數,每趟換種子,且經 /history 確認取樣節點沒有命中 ComfyUI 的節點快取。

128 GB 對生圖的真正意義

拿同一個工作流在兩台跑,四組對照。中型模型是 FLUX.1 Krea dev fp8,1024×1024、20 步、euler/simple,大模型是 FLUX.2 Klein base 9B 的 bf16 版,配官方指定的 Qwen3-8B text encoder 與 flux2-vae,一共約 25.3 GB。

Spark 桌機 5060 Ti
中型模型單張(Krea fp8,1024×1024,20 步) 18.38 秒 22.22 秒
大模型單張(Klein base 9B bf16,約 25.3 GB) 59.19 秒 73.81 秒
大模型首趟(含載入) 205.98 秒 90.22 秒
同時常駐模型數 1 1
換回上一款模型要多等 14.76 秒 5.96 秒
批次十張(每張換種子,總牆鐘) 225.22 秒 247.97 秒

第一個意外是中型模型單張的測試,Spark 居然領先 RTX 5060 Ti 21%,原本預期 16 GB VRAM 跑得動中型模型、頻寬又高應該會勝過 Spark。結果實際測試不是這樣。這兩台的差距在中型與大模型上幾乎一樣(21% 與 20%),因此並非記憶體效應,而是單純的算力差。

https://ithelp.ithome.com.tw/upload/images/20260905/20141816vYH4eegueQ.png

順帶回答一個讀者問的問題,如果是同一個種子,兩台生出來的圖會如何呢? 實測是這樣,儘管不是逐位元組相同,但差異小到沒有實際意義。平均每個通道差 1.322(滿格 255),PSNR 42.34 dB,差超過 8 的通道只佔 0.40%。兩台用的每一款權重我都確認過是位元組相同的檔案,圖片的微小差異,來自不同 GPU 的核心實作。

第二個意外,也是今天最有意思的,128 GB 統一記憶體沒有讓多個模型同時常駐。原本以為這是 Spark 的主場,但實測後發現不是。這次測試的做法是跑 A(Krea)、再跑 A、再跑 B(Klein)、再跑回 A,看第四趟要多久:

趟次 Spark 桌機
A 第一次(冷) 76.46 秒 28.30 秒
A 第二次(常駐) 18.41 秒 22.78 秒
B(換大模型) 139.89 秒 77.26 秒
A 第三次(換回來) 33.17 秒 28.74 秒

兩台機器都沒有維持常駐,換不同模型都要多付一次載入的時間成本。而且 Spark 付得比桌機更久,14.76 秒對 5.96 秒。

查 ComfyUI 的日誌,可以看到這段蠻清楚的:

0 models unloaded.
VAE load device: cuda:0, offload device: cpu, dtype: torch.bfloat16
Requested to load FluxClipModel_
Requested to load Flux

模型根本沒有被卸載。那 14.76 秒是把權重從 offload device(cpu)搬回 load device(cuda:0)。而在 GB10 上,這兩個「裝置」是同樣的 LPDDR5X 記憶體。22.03 GB 除以 14.76 秒是 1.49 GB/s,而桌機這段則是走真正的 PCIe,同樣的 22.03 GB 只花 5.96 秒,是 3.70 GB/s。

在統一記憶體上,把資料從記憶體搬到同一塊記憶體,比在分離式架構上真的走一趟 PCIe 還慢。這跟 Day 22 文章中的結論是同一件事的另一面。那天測試 FreeToken 時,在這個任務中測到 Spark 的「PCIe 頻寬」58.8 GB/s,測的其實是同樣 DRAM 的複製速度,今天 ComfyUI 照著 VRAM 與系統記憶體的二分法搬權重,在一台沒有那座橋的機器上,仍然照原價付了過橋費。

因此 Day 22 的說法可以直接沿用,看到任何一個宣稱能加速的最佳化,先問它在解哪一種記憶體架構的問題。差別是那天 FreeToken 自己在執行程式自己測完就識相地不啟用,但今天 ComfyUI 不會,它照做不誤。

那 128 GB 到底換到了什麼? 換到「不會失敗」與「不必先做取捨」。桌機跑 25.3 GB 的大模型不是跑不動,Windows 的共用 GPU 記憶體能夠讓它跑,代價是至少慢 20% 以上,碰到更大權重的模型,在 Windows 桌機上,GPU 和 CPU 會更高頻率地反覆卸載和讀取、搬資料,連帶地影響 AI 產圖效率,如果是影片那就得花更長時間了喔。

https://ithelp.ithome.com.tw/upload/images/20260905/201418163NSJVtGTta.png

來看 Windows 11 的工作管理員,顯示得很清楚,專用 GPU 記憶體 14.0 / 16.0 GB 貼在上限(中間那個凹陷是 ComfyUI 卸載模型再重載),共用 GPU 記憶體從接近 0 爬到 25 / 102 GB,GPU 使用率 99%、74 度。我在同一段時間每秒輪詢桌機自己回報的數字,VRAM 峰值用到 15.30 GiB(共 15.90 GiB),餘量只剩 0.60 GiB,系統記憶體則還有 60.1 GiB 沒動用。16 GB VRAM 加 128 GB DRAM 系統記憶體的組合,實際呈現的樣子如斯。

因此真正的差別會在再往上一階出現,我這個庫裡最大的是 38 GB 的 Qwen-Image-Edit 2511 bf16,配上它的 text encoder 超過 47 GB,那時候 16 GB 這一側就會慢更多。

所以「AI 產圖或產影片的人該買哪一種?」,我的答案跟本系列原先構想的一樣,但理由有變動了,答案是兩種都要,一台快手一台重工,只是誰快手誰重工跟我原本想的相反。Spark 在單張與批次都領先,桌機的優勢在換模型便宜(5.96 秒對 14.76 秒),適合一天到晚在不同模型之間跳的探索型工作,Spark 適合選定一款模型之後把它跑滿。NAS 集中庫讓兩台不用各維護一份模型,這一點今天總算是真的做到實際效益了。

插播時事:2026 IFA 給生成媒體的兩個訊號

本週 2026 IFA 的 NVIDIA 新聞稿裡有兩條跟這週的文章與主題直接相關。LTX 2.5 這款開放權重影片模型針對 DGX Spark 推出了 NVFP4 與 ComfyUI 的增強,記憶體效率與速度都有更新,值得排進本週的工作流。更大的一條是 FastVideo 與 NVIDIA 合作發布了 FastH3,MiniMax-H3 的四步蒸餾版,宣稱效能提升七倍,DGX Spark 的最佳化 recipe 也推出。

明天正好輪到 MiniMax-H3 與我的 h3-ui,蒸餾版對原版的實測會直接排進去。

明天預告

生圖環境就位,明天進影片,測試 MiniMax-H3 的地端影片生成、我為它寫的 h3-ui 前端(佇列、種子、可重現的 sidecar 設計)、以及那個讓我踩到 vLLM-Omni 上游 bug 的除錯,再加上剛出爐的 FastH3 蒸餾版對決原版。

我們 Day 24 見囉。

(本篇所有數字為本機實測。兩台機器都跑 ComfyUI 官方範本轉成的 API 格式工作流,時間取自 ComfyUI 自己 /history 回報的伺服器端執行時間,不是碼表,每一趟換種子,並在取驗前檢查 execution_cached 確認關鍵節點未命中節點快取,載入實測的冷快取狀態以 mincore 驗證,量測前殘留 0.04%。)

Day 1|為什麼 2026 年是地端 AI 部署元年:系列規劃與硬體總覽
Day 2|DGX Spark GB10 深度解析:128GB 統一記憶體到底解決了什麼問題
Day 3|網路與儲存規劃:10GbE 骨幹、雙 Spark 直連與 NFS 集中模型庫
Day 4|開箱之後:DGX OS 初始環境建置與 CUDA、Docker 生態確認
Day 5|NFS 模型庫實戰:下載工具、權限設計與版本管理
Day 6|llama.cpp、vLLM、TensorRT-LLM 、Ollama、DS4 與 Unsloth 的定位與取捨
Day 7|第一個模型上線:gpt-oss-120b 從模型庫到 API 的完整流程
Day 8|llama.cpp 實測:先定量尺與 SOP
Day 9|vLLM 實測:官方容器、同時處理吞吐曲線,與剛出爐的新模型 Ornith 1.5
Day 10|TensorRT-LLM 實測:我花了一個下午,跟它的預設值搏感情
Day 11|地端 AI 三大推論引擎綜合評測,同場加映神秘嘉賓
Day 12|量化格式解析:「4-bit」兩個字,古今多少事 ? 都付笑談中
Day 13|Perplexity 把整套 Agent 搬上 DGX Spark:地端元年的官方背書
Day 14|Qwen3.8-27B 與 Flash-Next 加碼實測:地端模型世代對決與落地評估
Day 15|Ornith 1.5 實測:為 AI agent 而生的 35B-A3B
Day 16|模型選型方法論:五個問題幫你跳脫排行榜迷失,找到適合自己任務用的 AI 模型
Day 17|ds4 深度解析:Redis 之父只為一種模型造了一個引擎
Day 18|OpenAI 相容 API 層:地端 AI 多模型常駐好助手
Day 19|地端 agent 框架總覽:它們到底對你的端點做了什麼呢?
Day 20|DeepSeek Harness 實戰:21 萬顆星的外掛式 harness 接上地端
Day 21|herdr 是地端 AI 同時跑多個 AI agent 的最佳解
Day 22|語意錨點對上 prefix cache,FreeToken VS vLLM,以及三個關於統一記憶體的教訓
Day 23|ComfyUI 部署與 NFS 模型庫整合:把集中管理的哲學帶進生圖世界
Day 23|ComfyUI 部署與 NFS 模型庫整合:把集中管理的哲學帶進生圖世界
Day 24|MiniMax-H3 地端影片生成:h3-ui 與四步蒸餾版的三段對決
Day 25|Unsloth 微調實戰:教一款模型用繁體中文思考,並遵守台灣的編輯規範
Day 26|微調的最後一哩路:合併、轉檔、量化、上線


上一篇
Day 22|語意錨點對上 prefix cache,FreeToken VS vLLM,以及三個關於統一記憶體的教訓
下一篇
Day 24|MiniMax-H3 地端影片生成:h3-ui 與四步蒸餾版的三段對決
系列文
128GB 統一記憶體的三十天:DGX Spark 地端 LLM 與生成式 AI 部署實戰28
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言